#include "iblog_in.h"

int OnAcceptingSocket( struct IblogEnv *p_env , struct ListenSession *p_listen_session )
{
	struct AcceptedSession	*p_accepted_session = NULL ;
	SOCKLEN_T		accept_addr_len ;
	
	struct epoll_event	event ;
	
	int			nret = 0 ;
	
	p_accepted_session = (struct AcceptedSession *)malloc( sizeof(struct AcceptedSession) ) ;
	if( p_accepted_session == NULL )
	{
		ERRORLOGG( "malloc failed , errno[%d]" , errno );
		return 1;
	}
	memset( p_accepted_session , 0x00 , sizeof(struct AcceptedSession) );
	
	accept_addr_len = sizeof(struct sockaddr) ;
	p_accepted_session->netaddr.sock = accept( p_listen_session->netaddr.sock , (struct sockaddr *) & (p_accepted_session->netaddr.addr) , & accept_addr_len ) ;
	if( p_accepted_session->netaddr.sock == -1 )
	{
		ERRORLOGG( "accept failed , errno[%d]" , errno );
		free( p_accepted_session );
		return 1;
	}
	
	SetHttpNonblock( p_accepted_session->netaddr.sock );
	SetHttpNodelay( p_accepted_session->netaddr.sock , 1 );
	SetHttpLinger( p_accepted_session->netaddr.sock , -1 );
	
	GETNETADDRESS( p_accepted_session->netaddr )
	
	p_accepted_session->comm_buf = (char*)malloc( IBLOG_COMMBUFFER_INIT_SIZE + 1 ) ;
	if( p_accepted_session->comm_buf == NULL )
	{
		ERRORLOGG( "malloc failed , errno[%d]" , errno );
		free( p_accepted_session );
		return 1;
	}
	memset( p_accepted_session->comm_buf , 0x00 , IBLOG_COMMBUFFER_INIT_SIZE + 1 );
	p_accepted_session->comm_buf_size = IBLOG_COMMBUFFER_INIT_SIZE + 1 ;
	p_accepted_session->comm_data_len = 0 ;
	p_accepted_session->comm_body_len = 0 ;
	
	p_accepted_session->p_log_handle = NULL ;
	
	memset( & event , 0x00 , sizeof(struct epoll_event) );
	event.events = EPOLLIN | EPOLLERR ;
	event.data.ptr = p_accepted_session ;
	nret = epoll_ctl( p_env->epoll_fd , EPOLL_CTL_ADD , p_accepted_session->netaddr.sock , & event ) ;
	if( nret == -1 )
	{
		ERRORLOGG( "epoll_ctl[%d] add[%d] failed , errno[%d]" , p_env->epoll_fd , p_accepted_session->netaddr.sock , errno );
		close( p_accepted_session->netaddr.sock );
		free( p_accepted_session );
		return 1;
	}
	else
	{
		DEBUGLOGG( "epoll_ctl[%d] add[%d] ok" , p_env->epoll_fd , p_accepted_session->netaddr.sock );
	}
	
	list_add_tail( & (p_accepted_session->this_node) , & (p_env->accepted_session_list.this_node) );
	
	return 0;
}

void OnClosingSocket( struct IblogEnv *p_env , struct AcceptedSession *p_accepted_session )
{
	if( p_accepted_session )
	{
		if( p_accepted_session->p_log_handle )
		{
			p_accepted_session->p_log_handle->ref_count--;
			if( p_accepted_session->p_log_handle->ref_count == 0 )
			{
				UnlinkIblogHandleTreeNode( p_env , p_accepted_session->p_log_handle );
				DestroyLogHandle( p_accepted_session->p_log_handle->g );
				free( p_accepted_session->p_log_handle );
			}
		}
		
		INFOLOGG( "close session[%p]" , p_accepted_session );
		epoll_ctl( p_env->epoll_fd , EPOLL_CTL_DEL , p_accepted_session->netaddr.sock , NULL );
		close( p_accepted_session->netaddr.sock );
		list_del( & (p_accepted_session->this_node) );
		free( p_accepted_session->comm_buf );
		free( p_accepted_session );
	}
	
	return;
}

int OnReceivingSocket( struct IblogEnv *p_env , struct AcceptedSession *p_accepted_session )
{
	int			len ;
	
	int			nret = 0 ;
	
	if( p_accepted_session->comm_data_len == p_accepted_session->comm_buf_size-1 )
	{
		char	*tmp = NULL ;
		
		tmp = (char*)realloc( p_accepted_session->comm_buf , p_accepted_session->comm_buf_size+IBLOG_COMMBUFFER_INCREASE_SIZE ) ;
		if( tmp == NULL )
		{
			ERRORLOGG( "malloc failed , errno[%d]" , errno );
			return 1;
		}
		p_accepted_session->comm_buf = tmp ;
		p_accepted_session->comm_buf_size += IBLOG_COMMBUFFER_INCREASE_SIZE ;
	}
	
	DEBUGLOGG( "read [%d] bytes at most ..." , p_accepted_session->comm_buf_size-1-p_accepted_session->comm_data_len );
	len = read( p_accepted_session->netaddr.sock , p_accepted_session->comm_buf+p_accepted_session->comm_data_len , p_accepted_session->comm_buf_size-1-p_accepted_session->comm_data_len ) ;
	if( len == -1 )
	{
		ERRORLOGG( "recv failed[%d] , errno[%d]" , len , errno );
		return 1;
	}
	else if( len == 0 )
	{
		INFOLOGG( "remote socket closed" );
		return 1;
	}
	else
	{
		DEBUGHEXLOGG( p_accepted_session->comm_buf+p_accepted_session->comm_data_len , len , "recv [%d]bytes" , len );
		p_accepted_session->comm_data_len += len ;
	}
	
_GOTO_REPEAT :
	
	if( p_accepted_session->comm_data_len >= 4 )
	{
		if( p_accepted_session->comm_body_len == 0 )
		{
			p_accepted_session->comm_body_len = ntohl( *(uint32_t*)(p_accepted_session->comm_buf) ) ;
		}
		
		if( p_accepted_session->comm_data_len >= 4+p_accepted_session->comm_body_len )
		{
			char		bak ;
			
			bak = p_accepted_session->comm_buf[4+p_accepted_session->comm_body_len] ;
			p_accepted_session->comm_buf[4+p_accepted_session->comm_body_len] = '\0' ;
			DEBUGHEXLOGG( p_accepted_session->comm_buf , 4+p_accepted_session->comm_body_len , "processing [%d]bytes" , 4+p_accepted_session->comm_body_len );
			nret = OnAppProcess( p_env , p_accepted_session ) ;
			p_accepted_session->comm_buf[4+p_accepted_session->comm_body_len] = bak ;
			if( nret != HTTP_OK )
			{
				ERRORLOGG( "OnAppProcess failed[%d] , errno[%d]" , nret , errno );
				return 1;
			}
			
			memmove( p_accepted_session->comm_buf , p_accepted_session->comm_buf+4+p_accepted_session->comm_body_len , p_accepted_session->comm_data_len-4-p_accepted_session->comm_body_len );
			p_accepted_session->comm_data_len -= 4+p_accepted_session->comm_body_len ;
			p_accepted_session->comm_body_len = 0  ;
			goto _GOTO_REPEAT;
		}
	}
	
	return 0;
}

